package moltencore.game;

import moltencore.game.bubble.Type;

public class Settings {
	private static final int DEFAULT_CRITICAL_MASS = 3;
	public static final int MIN_PlAYERS = 1;
	public static final int MAX_PLAYERS = 5;
	public static final int MIN_CRITICAL_MASS = 2;
	public static final int MAX_CRITICAL_MASS = 6;
	public static final int MIN_ORDINARY_BUBBLE_COUNT = 2;
	public static final int MAX_ORDINARY_BUBBLE_COUNT = Type.ORDINARY_BUBBLE_COUNT;

	private Game.Mode mode;
	private String name;
	private int playerLimit;
	private int teamSize;
	private int criticalMass = DEFAULT_CRITICAL_MASS;
	private boolean gravity = false;
	private boolean wind = false;
	private int ordinaryBubbleCount = MAX_ORDINARY_BUBBLE_COUNT;
	private boolean chainReactions = false;
	private int pushCount;
	private float ordinaryBubbleProbability;
	private float rainbowBubbleProbability;
	private float ghostBubbleProbability;
	private float blazingBubbleProbability;

	public Settings() {
	}

	public Settings(Game.Mode mode, String name, int playerLimit, int teamSize, int criticalMass, boolean gravity, boolean wind, int ordinaryBubbleCount, boolean chainReactions, int pushCount, float ordinaryBubbleProbability, float rainbowBubbleProbability, float ghostBubbleProbability, float blazingBubbleProbability) {
		setPlayerLimit(playerLimit);
		setCriticalMass(criticalMass);
		setOrdinaryBubbleCount(ordinaryBubbleCount);
		this.teamSize = teamSize;
		this.mode = mode;
		this.name = name;
		this.gravity = gravity;
		this.wind = wind;
		this.chainReactions = chainReactions;
		this.pushCount = pushCount;
		this.ordinaryBubbleProbability = ordinaryBubbleProbability;
		this.rainbowBubbleProbability = rainbowBubbleProbability;
		this.ghostBubbleProbability = ghostBubbleProbability;
		this.blazingBubbleProbability = blazingBubbleProbability;
	}

	public Settings(Settings settings) {
		this(settings.mode, settings.name, settings.playerLimit, settings.teamSize, settings.criticalMass, settings.gravity, settings.wind,
		     settings.ordinaryBubbleCount, settings.chainReactions, settings.pushCount,
		     settings.ordinaryBubbleProbability, settings.rainbowBubbleProbability, settings.ghostBubbleProbability, settings.blazingBubbleProbability);
	}

	public int getCriticalMass() {
		return criticalMass;
	}

	public void setCriticalMass(int criticalMass) throws InvalidCriticalMassException {
		if(criticalMass < MIN_CRITICAL_MASS || criticalMass > MAX_CRITICAL_MASS) {
			throw new InvalidCriticalMassException("Critical mass must be between " + MIN_CRITICAL_MASS + " and " + MAX_CRITICAL_MASS);
		}
		this.criticalMass = criticalMass;
	}

	public boolean isGravity() {
		return gravity;
	}

	public void setGravity(boolean gravity) {
		this.gravity = gravity;
	}

	public boolean isWind() {
		return wind;
	}

	public void setWind(boolean wind) {
		this.wind = wind;
	}

	public boolean isChainReactions() {
		return chainReactions;
	}

	public void setChainReactions(boolean chainReactions) {
		this.chainReactions = chainReactions;
	}

	public int getOrdinaryBubbleCount() {
		return ordinaryBubbleCount;
	}

	public void setOrdinaryBubbleCount(int ordinaryBubbleCount) {
		if(ordinaryBubbleCount < MIN_ORDINARY_BUBBLE_COUNT || ordinaryBubbleCount > MAX_ORDINARY_BUBBLE_COUNT) {
			throw new InvalidOrdinaryBubbleCountException("Ordinary bubble count must be between " + MIN_ORDINARY_BUBBLE_COUNT + " and " + MAX_ORDINARY_BUBBLE_COUNT);
		}
		this.ordinaryBubbleCount = ordinaryBubbleCount;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getPlayerLimit() {
		return playerLimit;
	}

	public void setPlayerLimit(int playerLimit) {
		if(playerLimit < MIN_PlAYERS || playerLimit > MAX_PLAYERS) {
			throw new InvalidPlayerLimitException("Limit must be between " + MIN_PlAYERS + " and " + MAX_PLAYERS);
		}
		this.playerLimit = playerLimit;
	}

	public Game.Mode getMode() {
		return mode;
	}

	public void setMode(Game.Mode mode) {
		this.mode = mode;
	}

	public int getPushCount() {
		return pushCount;
	}

	public float getOrdinaryBubbleProbability() {
		return ordinaryBubbleProbability;
	}

	public float getRainbowBubbleProbability() {
		return rainbowBubbleProbability;
	}

	public float getGhostBubbleProbability() {
		return ghostBubbleProbability;
	}

	public float getBlazingBubbleProbability() {
		return blazingBubbleProbability;
	}

	public int getTeamSize() {
		return teamSize;
	}

	public boolean isTeamsEnabled() {
		return teamSize > 1;
	}

	public void setTeamSize(int teamSize) {
		this.teamSize = teamSize;
	}

	public void setPushCount(int pushCount) {
		this.pushCount = pushCount;
	}

	public void setOrdinaryBubbleProbability(float ordinaryBubbleProbability) {
		this.ordinaryBubbleProbability = ordinaryBubbleProbability;
	}

	public void setRainbowBubbleProbability(float rainbowBubbleProbability) {
		this.rainbowBubbleProbability = rainbowBubbleProbability;
	}

	public void setGhostBubbleProbability(float ghostBubbleProbability) {
		this.ghostBubbleProbability = ghostBubbleProbability;
	}

	public void setBlazingBubbleProbability(float blazingBubbleProbability) {
		this.blazingBubbleProbability = blazingBubbleProbability;
	}

	public class InvalidCriticalMassException extends RuntimeException {
		public InvalidCriticalMassException(String s) {
			super(s);
		}
	}

	public class InvalidOrdinaryBubbleCountException extends RuntimeException {
		public InvalidOrdinaryBubbleCountException(String s) {
			super(s);
		}
	}

	public class InvalidPlayerLimitException extends RuntimeException {
		public InvalidPlayerLimitException(String s) {
			super(s);
		}
	}
}
